package ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.devicecontroller.imp;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import ar.edu.utn.frsf.proyectofinal.sistemadecontrolmodbus.devicecontroller.ProcessImageDated;
import net.wimpi.modbus.procimg.DigitalIn;
import net.wimpi.modbus.procimg.DigitalOut;
import net.wimpi.modbus.procimg.IllegalAddressException;
import net.wimpi.modbus.procimg.InputRegister;
import net.wimpi.modbus.procimg.Register;

public class ProcessImageImp implements ProcessImageDated {

	private Map<Integer,DigitalIn>     digitalInputs;
	private Map<Integer,DigitalOut>    digitalOutputs;
	private Map<Integer,InputRegister> registerInputs;
	private Map<Integer,Register>      registerOutputs;
	
	private Map<Integer,Date>  digitalInputDate;         
	private Map<Integer,Date>  digitalOutputDate;
	private Map<Integer,Date>  registerInputDate;
	private Map<Integer,Date>  registerOutputDate;
	
	private Map<Integer, Object>  digitalInputLock;         
	private Map<Integer, Object>  digitalOutputLock;
	private Map<Integer, Object>  registerInputLock;
	private Map<Integer, Object>  registerOutputLock;
	
	public static int MAP_SIZE = 150;
	//public static final Integer INT_1 = new Integer(1);
		//public static final Integer INT_0 = new Integer(0);
	
	public ProcessImageImp() {
		
		digitalInputs   = new HashMap<Integer,DigitalIn>    (MAP_SIZE);
		digitalOutputs  = new HashMap<Integer,DigitalOut>   (MAP_SIZE);
		registerInputs  = new HashMap<Integer,InputRegister>(MAP_SIZE);
		registerOutputs = new HashMap<Integer,Register>     (MAP_SIZE);
		
		digitalInputDate   = new HashMap<Integer,Date>(MAP_SIZE);         
		digitalOutputDate  = new HashMap<Integer,Date>(MAP_SIZE);
		registerInputDate  = new HashMap<Integer,Date>(MAP_SIZE);
		registerOutputDate = new HashMap<Integer,Date>(MAP_SIZE);
		
		digitalInputLock   = new HashMap<Integer,Object>(MAP_SIZE);         
		digitalOutputLock  = new HashMap<Integer,Object>(MAP_SIZE);
		registerInputLock  = new HashMap<Integer,Object>(MAP_SIZE);
		registerOutputLock = new HashMap<Integer,Object>(MAP_SIZE);
		
	}
	
	/* ************************************************
	 *  DIGITAL-IN METHODS 
	 * ************************************************/
	
	@Override
	public DigitalIn getDigitalIn(int index) throws IllegalAddressException {
		
		if(digitalInputLock.containsKey(index))
			synchronized (digitalInputLock.get(index)) {
		        return digitalInputs.get(index);
			}
		
		throw new IllegalAddressException();
		
	}
 
	@Override
	public int getDigitalInCount() {
		return digitalInputs.size();
	}

	@Override
	public void setDigitalIn(int index, DigitalIn dig, Date date)
			throws IllegalAddressException {
		
		if(!digitalInputLock.containsKey(index)) 
			digitalInputLock.put(index, new Object());
		
		synchronized (digitalInputLock.get(index)) {
			digitalInputs.put(index,dig);
			digitalInputDate.put(index, date);
		}		
		
	}

	@Override
	public Date getDigitalInDate(int index) throws IllegalAddressException {
		
		if(digitalInputLock.containsKey(index))
			synchronized (digitalInputLock.get(index)) {
		        return digitalInputDate.get(index);
			}
		
		throw new IllegalAddressException();	
		
	}

	/* ************************************************
	 *  DIGITAL-OUT METHODS 
	 * ************************************************/
	
	@Override
	public DigitalOut getDigitalOut(int index) throws IllegalAddressException {

		if(digitalOutputLock.containsKey(index))
			synchronized (digitalOutputLock.get(index)) {
		        return digitalOutputs.get(index);
			}
		
		throw new IllegalAddressException();
		
	}

	@Override
	public int getDigitalOutCount() {
		
		return digitalOutputs.size();
		
	}

	@Override
	public void setDigitalOut(int index, DigitalOut dig, Date date)
			throws IllegalAddressException {
		
		if(!digitalOutputLock.containsKey(index)) 
			digitalOutputLock.put(index, new Object());
	
		synchronized (digitalOutputLock.get(index)) {
			digitalOutputs.put(index,dig);
			digitalOutputDate.put(index, date);
		}	
		
	}

	@Override
	public Date getDigitalOutDate(int index) throws IllegalAddressException {
		
		if(digitalOutputLock.containsKey(index))
			synchronized (digitalOutputLock.get(index)) {
		        return digitalOutputDate.get(index);
			}
		
		throw new IllegalAddressException();	
		
	}

	/* ************************************************
	 *  INPUT-REGISTER METHODS 
	 * ************************************************/
	
	@Override
	public InputRegister getInputRegister(int index)
			throws IllegalAddressException {

		if(registerInputLock.containsKey(index))
			synchronized (registerInputLock.get(index)) {
		        return registerInputs.get(index);
			}
		
		throw new IllegalAddressException();	
		
	}

	@Override
	public int getInputRegisterCount() {
		
		return registerInputs.size();
		
	}
	
	@Override
	public void setInputRegister(int index, InputRegister reg, Date date)
			throws IllegalAddressException {
		
		if(!registerInputLock.containsKey(index)) 
			registerInputLock.put(index, new Object());
		
		synchronized (registerInputLock.get(index)) {
			registerInputs.put(index,reg);
			registerInputDate.put(index, date);
		}		
		
	}

	@Override
	public Date getInputRegisterDate(int ref) throws IllegalAddressException {
		
		if(registerInputLock.containsKey(ref))
			synchronized (registerInputLock.get(ref)) {
		        return registerInputDate.get(ref);
			}
		
		throw new IllegalAddressException();
		
	}

	/* ************************************************
	 *  REGISTER METHODS 
	 * ************************************************/
	
	@Override
	public Register getRegister(int index) throws IllegalAddressException {

		if(registerOutputLock.containsKey(index))
			synchronized (registerOutputLock.get(index)) {
		        return registerOutputs.get(index);
			}
		
		throw new IllegalAddressException();	
		
	}

	@Override
	public int getRegisterCount() {
		
		return registerOutputs.size();
		
	}

	@Override
	public void setRegister(int index, Register reg, Date date)
			throws IllegalAddressException {
		
		if(!registerOutputLock.containsKey(index)) 
			registerOutputLock.put(index, new Object());
		
		synchronized (registerOutputLock.get(index)) {
			registerOutputs.put(index,reg);
			registerOutputDate.put(index, date);
		}		
		
	}

	@Override
	public Date getRegisterDate(int ref) throws IllegalAddressException {
		
		if(registerOutputLock.containsKey(ref))
			synchronized (registerOutputLock.get(ref)) {
		        return registerOutputDate.get(ref);
			}
		
		throw new IllegalAddressException();	
		
	}

}
